<template>
  <div style="margin: auto">
    <canvas id="cvs" style="background-color: #000"></canvas>
  </div>
</template>

<script lang="ts" setup>
import { onMounted } from 'vue'

onMounted(() => {
  const cvs: HTMLCanvasElement | null = document.querySelector('#cvs')
  cvs && renderCvs(cvs)
})

function renderCvs(cvs: HTMLCanvasElement) {
  const ctx = cvs.getContext('2d') as CanvasRenderingContext2D
  const width = window.innerWidth
  const height = window.innerWidth > 760 ? 400 : 200
  cvs.width = width
  cvs.height = height
  ctx.fillStyle = '#ffffff'
  const bgColors = Array.from(new Array(400)).map((v) => {
    return {
      x: Math.random() * width,
      y: Math.random() * height,
      step: Math.random() * 2.5 + 0.5,
    }
  })
  type colors = {
    x: number
    y: number
    rx: any
    ry: any
    stepX: number
    stepY: number
  }
  let colors: colors[] = []
  const sendText = (text: string, fontSize = 100, stepV = 40) => {
    ctx.fillStyle = '#000000'
    ctx.fillRect(0, 0, width, height)
    ctx.font = `bold ${fontSize}px 微软雅黑`
    ctx.fillStyle = '#ffffff'
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'
    ctx.fillText(text, width / 2, height / 2)
    const data = ctx.getImageData(0, 0, width, height).data

    let index = 0
    let bl = 4
    let useIndex = 0
    for (let i = 0; i < data.length; i += 4) {
      const x = index % width
      const y = Math.ceil(index / width)
      if (
        x % bl === 0 &&
        y % bl === 0 &&
        data[i] === 255 &&
        data[i + 1] === 255 &&
        data[i + 2] === 255
      ) {
        const rx =
          Math.floor(Math.random() * fontSize) + width / 2 - fontSize / 2
        const ry =
          Math.floor(Math.random() * fontSize) + height / 2 - fontSize / 2

        const item = colors[useIndex]
        if (item) {
          colors[useIndex] = {
            x,
            y,
            rx: item.x,
            ry: item.y,
            stepX: Math.abs(item.x - x) / stepV,
            stepY: Math.abs(item.y - y) / stepV,
          }
        } else {
          colors[useIndex] = {
            x,
            y,
            rx,
            ry,
            stepX: Math.abs(rx - x) / stepV,
            stepY: Math.abs(ry - y) / stepV,
          }
        }
        useIndex++
      }
      index++
    }
    if (useIndex < colors.length) {
      colors.splice(useIndex, colors.length - useIndex)
    }
  }
  const render = () => {
    ctx.clearRect(0, 0, width, height)
    ctx.beginPath()
    colors.forEach((v) => {
      if (v.rx > v.x) {
        v.rx -= v.stepX
        if (v.rx < v.x) {
          v.rx = v.x
        }
      } else if (v.rx < v.x) {
        v.rx += v.stepX
        if (v.rx > v.x) {
          v.rx = v.x
        }
      }

      if (v.ry > v.y) {
        v.ry -= v.stepY
        if (v.ry < v.y) {
          v.ry = v.y
        }
      } else if (v.ry < v.y) {
        v.ry += v.stepY
        if (v.ry > v.y) {
          v.ry = v.y
        }
      }
      ctx.rect(v.rx, v.ry, 3, 3)
    })
    bgColors.forEach((v) => {
      v.y = v.y > height ? 0 : v.y + v.step
      ctx.rect(v.x, v.y, 3, 3)
    })

    ctx.fill()
    requestAnimationFrame(render)
  }
  render()
  const awaitSendText = async (
    txt: string,
    fontSize: number,
    stepV: number
  ) => {
    return new Promise((resolve) => {
      sendText(txt, fontSize, stepV)
      colors.sort((v) => Math.random() - 0.5)
      setTimeout(() => resolve(null), 2000 + (stepV > 40 ? 1000 : 0))
    })
  }
  const run = async () => {
    const text =
      `上李邕 - 李白，大鹏一日同风起，扶摇直上九万里，假令风歇时下来，犹能簸却沧溟水，世人见我恒殊调，闻余大言皆冷笑，宣父犹能畏后生，丈夫未可轻年少`.split(
        '，'
      )
    let fontSize = window.innerWidth > 760 ? 100 : 45
    for (let i = 0; i < text.length; i++) {
      await awaitSendText(text[i], fontSize, i === 0 ? 100 : 40)
    }
  }
  run()
}
</script>
